package com.azxcrm.project.monitor.workflow.common;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.azxcrm.common.utils.security.ShiroUtils;
import com.azxcrm.project.monitor.workflow.domain.WorkFlow;
import com.azxcrm.project.monitor.workflow.domain.WorkFlowApply;
import com.azxcrm.project.monitor.workflow.service.WorkFlowApplyService;
import com.azxcrm.project.monitor.workflow.service.WorkFlowService;
import com.azxcrm.project.system.basic.domain.OrderModifyRecord;
import com.azxcrm.project.system.basic.domain.RegisterUser;
import com.azxcrm.project.system.basic.service.IOrderModifyRecordService;
import com.azxcrm.project.system.basic.service.IRegisterUserService;
import com.azxcrm.project.system.order.domain.Order;
import com.azxcrm.project.system.order.service.IOrderService;
import com.azxcrm.project.system.role.dao.IRoleDao;
import com.azxcrm.project.system.role.domain.Role;
import com.azxcrm.project.system.user.dao.IUserDao;
import com.azxcrm.project.system.user.dao.IUserRoleDao;
import com.azxcrm.project.system.user.domain.User;
import com.azxcrm.project.system.user.domain.UserRole;

@Service("workFlowService")
public class CommonService {
	
	private static final Logger log = LoggerFactory.getLogger(CommonService.class);

	@Autowired
	IUserDao iUserDao;
	
	@Autowired
	IUserRoleDao iUserRoleDao;
	
	@Autowired
	IRoleDao iRoleDao;
	
	@Autowired
	private WorkFlowApplyService workFlowApplyService;
	
	@Autowired
	private WorkFlowService workFlowService;
	
	@Autowired
	private RuntimeService runtimeService;
	
	@Autowired
	private TaskService taskService;
	
	@Autowired
	private IOrderService orderService;
	
	@Autowired
	private IOrderModifyRecordService orderModifyRecordService;
	
	@Autowired
	private HistoryService historyService;

	@Autowired
	private static RepositoryService repositoryService;
	
	@Autowired
	private IRegisterUserService registerUserService;
	
	/**
	 * 部门经理角色Key
	 */
	@Value("${crm.role.departmentManager}")
	private String departmentManager;
	
	 /**
	 * 业务员角色Key
	 */
	 @Value("${crm.role.salesman}")
	 private String salesman; 
	
	 /**
	 * 财务角色Key
	 */
	 @Value("${crm.role.treasurer}")
	 private String treasurer;
	 
	 /**
	 * 财务角色Key
	 */
	 @Value("${crm.role.hr}")
	 private String hr;
	
	 /**
	  * 成单唯一标识
	  */
	 @Value("${crm.workflow.deal}")
	 private String dealProcess;
	 
	 /**
	  * 退单唯一标识
	  */
	 @Value("${crm.workflow.refund}")
	 private String refundProcess;
	 
	 
	 /**
	  * 注册审批唯一标识
	  */
	 @Value("${crm.workflow.register}")
	 private String registerProcess;
	 
	/**
	 * 启动流程
	 * 
	 */
	public void startProcess(String bizKey,WorkFlowApply workFlowApply) {
		// 第一个参数是指定启动流程的id,即要启动哪个流程 ;第二个参数是指业务id
		WorkFlow workFlow = workFlowService.selectWorkFlowById(workFlowApply.getFlowId());
		runtimeService.startProcessInstanceByKey(workFlow.getFlowCode(), bizKey);
		log.info("Set up"+workFlow.getFlowName()+"sucess");
	}

	/**
	 * 根据审批人id查询需要审批的任务
	 * 
	 * @param userId
	 * @return
	 */
	public List<Task> findTaskByUserId(String userId) {
		List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned(userId).list();
		return list;
	}

	/**
	 * 审批
	 * @param taskId
	 * 审批的任务id
	 * @param userId
	 *  审批人的id
	 * @param audit
	 * 审批意见：通过（pass）or驳回（reject）
	 */
	public void completeTaskByUser(String taskId, String userId, String audit) {
		Map<String, Object> map = new HashMap<>();
		// 1、认领任务
		taskService.claim(taskId, userId);
		// 2.完成任务
		map.put("audit", audit);
		taskService.complete(taskId, map);
	}

	/**
	 * 查询相关的项目经理
	 * 
	 * @param execution
	 *执行实例的代理对象 ,代表的是一个请假的具体实例
	 * 项目经理
	 * @return
	 */
	public List<String> findDepartmentManager(DelegateExecution execution) {
		List<String> userInfo = new ArrayList<>();
		List<UserRole> userRoleInfo = new ArrayList<>();
		//获取该实例的BusinessKey，对应表sys_work_flow_apply中的businessId
		String businessId = execution.getProcessInstanceBusinessKey();
		
		WorkFlowApply workFlowApply = workFlowApplyService.selectWorkFlowApplyByBusinessId(businessId);
		//若是订单类的审批则获取该订单的详情
		if(workFlowApply.getOrderId() != null){
			Order order = orderService.selectOrderById(workFlowApply.getOrderId());
			userRoleInfo =iUserRoleDao.selectUserByRoleKeyByParam(departmentManager, order.getDeptId());
		}
		
		//非订单类审批
		else if(workFlowApply.getRegisterId() !=null && workFlowApply.getRegisterId() > 0) {
			RegisterUser  registerUser = registerUserService.selectRegisterUserById(workFlowApply.getRegisterId());
			userRoleInfo =iUserRoleDao.selectUserByRoleKeyByParam(departmentManager, registerUser.getRegisterDeptid());
		}
		
		if(userRoleInfo.size() > 0 && userRoleInfo != null) {
			for (UserRole userRole : userRoleInfo) {
				userInfo.add(String.valueOf(userRole.getUserId()));
			}
		}
		return userInfo;
	}

	/**
	 * 查询相关的人事经理
	 * 
	 * @param execution
	 * 执行实例的代理对象,代表的是一个请假的具体实例
	 * 人事经理
	 * @return
	 */
	public List<String> findHRManager(DelegateExecution execution) {
		List<String> userInfo = new ArrayList<>();
		List<UserRole> userRoleInfo = new ArrayList<>();
		userRoleInfo = iUserRoleDao.selectUserByRoleKey(hr);
		if (userRoleInfo.size() > 0 && userRoleInfo != null) {
			for (UserRole userRole : userRoleInfo) {
				userInfo.add(String.valueOf(userRole.getUserId()));
			}
		}
		return userInfo;
	}
	
	/**
	 * 查询财务
	 * 
	 * @param execution
	 * 执行实例的代理对象,代表的是一个请假的具体实例
	 * 财务
	 * @return
	 */
	public List<String> findTreasurer(DelegateExecution execution) {
		List<String> userInfo = new ArrayList<>();
		List<UserRole> userRoleInfo = new ArrayList<>();
		userRoleInfo = iUserRoleDao.selectUserByRoleKey(treasurer);
		if (userRoleInfo.size() > 0 && userRoleInfo != null) {
			for (UserRole userRole : userRoleInfo) {
				userInfo.add(String.valueOf(userRole.getUserId()));
			}
		}
		return userInfo;
	}
	
	

	/**
	 * 修改流程以及订单状态
	 * @param execution
	 * @param status
	 */
	public void changeStatus(DelegateExecution execution, String status) {
		//过去当前审批人信息
		Subject subject = SecurityUtils.getSubject();
		String businessId = execution.getProcessInstanceBusinessKey();
		WorkFlowApply workFlowApply = workFlowApplyService.selectWorkFlowApplyByBusinessId(businessId);

		// 部门经理审批逻辑
		if (subject.hasRole("departmentManager")) {
			// 退单逻辑
			if (workFlowApply.getOrderId() != null && refundProcess.equals(workFlowApply.getWorkFlow().getFlowCode())) {
				if ("reject".equals(status)) {
					// 退单逻辑部门经理审批，且审批意见为reject时，修改订单状态
					// 审核被拒时还原订单状态：已成单且审核状态为审核被拒
					Order order = new Order(workFlowApply.getOrderId(), 5, null, 3);
					orderService.updateOrder(order);

					// 新增订单修改记录
					OrderModifyRecord orderModifyRecord = new OrderModifyRecord(workFlowApply.getOrderId(),
							ShiroUtils.getUserId().intValue(), 2, "退单审核被拒");
					orderModifyRecordService.insertOrderModifyRecord(orderModifyRecord);
				}
			}
			
			// 注册逻辑流程
			if (workFlowApply.getRegisterId() != null && registerProcess.equals(workFlowApply.getWorkFlow().getFlowCode())) {
				if ("pass".equals(status)) {
					//审核通过
					//更新业务员注册表信息
					RegisterUser registerUser = registerUserService.selectRegisterUserById(workFlowApply.getRegisterId());
					registerUser.setRegisterAuditType(2);
					registerUserService.updateRegisterUser(registerUser);
					//用户表新增记录
					User user = new User();
					user.setDeptId(registerUser.getRegisterDeptid().longValue());
					user.setLoginName(registerUser.getRegisterLoginname());
					user.setUserName(registerUser.getRegisterRealname());
					user.setPhonenumber(registerUser.getRegisterPhonenum());
					user.setSex(registerUser.getRegisterSex());
					user.setPassword(registerUser.getRegisterPassword());
					user.setSalt(registerUser.getRegisterSalt());
					user.setAccessLogin(0);
					iUserDao.insertUser(user);
					//给该新增用户添加业务员角色
					Role role = iRoleDao.selectRoleByRoleKey(salesman);
					UserRole userRole = new UserRole();
					userRole.setRoleId(role.getRoleId());
					userRole.setUserId(user.getUserId());
					user.setUserRole(userRole);
					iUserRoleDao.insertUserRole(userRole);
				}
				if ("reject".equals(status)) {
					//审核不通过
					//更新业务员注册表信息
					RegisterUser registerUser = registerUserService.selectRegisterUserById(workFlowApply.getRegisterId());
					registerUser.setRegisterAuditType(1);
					registerUserService.updateRegisterUser(registerUser);
				}
			}
			
		}
		workFlowApply.setStatus(status);
		workFlowApplyService.updateWorkFlowApply(workFlowApply);
	}

	/**
	 * 根据流程id查看该流程是否结束
	 * 
	 * @param processInstanceId
	 * @return
	 */
	public boolean queryProcessIsEnd(String processInstanceId) {

		HistoricProcessInstance result = historyService.createHistoricProcessInstanceQuery()
				.processInstanceId(processInstanceId).singleResult();
		if (result != null && result.getStartTime() != null && result.getEndTime() != null) {
			return true;
		}
		return false;
	}

	/**
	 * 获取流程图
	 * 
	 * @param processDefId
	 * @return
	 */
	public static InputStream findProcessPic(String processDefId) {
		ProcessDefinition result = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefId)
				.singleResult();
		String name = result.getDiagramResourceName();
		InputStream inputStream = repositoryService.getResourceAsStream(result.getDeploymentId(), name);
		return inputStream;
	}
	
	public List<String> getExecutedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
        // 流转线ID集合
        List<String> flowIdList = new ArrayList<String>();
        // 全部活动实例
        List<FlowNode> historicFlowNodeList = new LinkedList<FlowNode>();
        // 已完成的历史活动节点
        List<HistoricActivityInstance> finishedActivityInstanceList = new LinkedList<HistoricActivityInstance>();
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            historicFlowNodeList.add((FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true));
            if (historicActivityInstance.getEndTime() != null) {
                finishedActivityInstanceList.add(historicActivityInstance);
            }
        }
        
        // 遍历已完成的活动实例，从每个实例的outgoingFlows中找到已执行的
        FlowNode currentFlowNode = null;
        for (HistoricActivityInstance currentActivityInstance : finishedActivityInstanceList) {
            // 获得当前活动对应的节点信息及outgoingFlows信息
            currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
            List<SequenceFlow> sequenceFlowList = currentFlowNode.getOutgoingFlows();
            
            /**
             * 遍历outgoingFlows并找到已已流转的
             * 满足如下条件认为已已流转：
             * 1.当前节点是并行网关或包含网关，则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
             * 2.当前节点是以上两种类型之外的，通过outgoingFlows查找到的时间最近的流转节点视为有效流转
             */
            FlowNode targetFlowNode = null;
            if (BpmsActivityTypeEnum.PARALLEL_GATEWAY.getType().equals(currentActivityInstance.getActivityType())
                    || BpmsActivityTypeEnum.INCLUSIVE_GATEWAY.getType().equals(currentActivityInstance.getActivityType())) {
                // 遍历历史活动节点，找到匹配Flow目标节点的
                for (SequenceFlow sequenceFlow : sequenceFlowList) {
                    targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
                    if (historicFlowNodeList.contains(targetFlowNode)) {
                        flowIdList.add(sequenceFlow.getId());
                    }
                }
            } else {
                List<Map<String, String>> tempMapList = new LinkedList<Map<String,String>>();
                // 遍历历史活动节点，找到匹配Flow目标节点的
                for (SequenceFlow sequenceFlow : sequenceFlowList) {
                    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
                        if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
                            tempMapList.add(UtilMisc.toMap("flowId", sequenceFlow.getId(), "activityStartTime", String.valueOf(historicActivityInstance.getStartTime().getTime())));
                        }
                    }
                }
                
                // 遍历匹配的集合，取得开始时间最早的一个
                long earliestStamp = 0L;
                String flowId = null;
                for (Map<String, String> map : tempMapList) {
                    long activityStartTime = Long.valueOf(map.get("activityStartTime"));
                    if (earliestStamp == 0 || earliestStamp >= activityStartTime) {
                        earliestStamp = activityStartTime;
                        flowId = map.get("flowId");
                    }
                }
                flowIdList.add(flowId);
            }
        }
        return flowIdList;
    }
	
	/**
	 * 根据ProcessId获取流程实例历史记录
	 * @param processInstanceId
	 * @return
	 */
	public List<HistoricActivityInstance> getInstanceDetail(String processInstanceId){
		//查看该审批流程的各个进度
        List<HistoricActivityInstance> hais = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
        
        for (HistoricActivityInstance hai : hais) {
			System.out.print("activitiId:" + hai.getActivityId() + "，");
			System.out.print("name:" + hai.getActivityName() + "，");
			System.out.print("type:" + hai.getActivityType() + "，");
			System.out.print("pid:" + hai.getProcessInstanceId() + "，");
			System.out.print("assignee:" + hai.getAssignee() + "，");
			System.out.print("startTime:" + hai.getStartTime() + "，");
			System.out.print("endTime:" + hai.getEndTime() + "，");
			System.out.println("duration:" + hai.getDurationInMillis());
		}
        
        return hais;
	}
	
}
